﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using nHydrate.SyncServer.Client;
using nHydrate.SyncServer.Service.Interfaces;

namespace nHydrate.Dsl.Custom
{
	public static class SyncServerManagement
	{
		public static void Load(nHydrateModel model)
		{
			if (model.SyncServerToken == Guid.Empty)
			{
				model.SyncServerToken = SyncDomain.ShowLoginPrompt(model.SyncServerURL);
				if (model.SyncServerToken == Guid.Empty)
				{
					MessageBox.Show("The server could not be contacted and the model cannot be loaded.", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Information);
					return;
				}
			}

			using (var transaction = model.Store.TransactionManager.BeginTransaction(Guid.NewGuid().ToString()))
			{
				var elements = new List<TransferModelItem>();
				elements.AddRange(SyncDomain.GetModel(model.SyncServerURL, model.SyncServerToken, model.Id));
				LoadEntities(model, elements);
				transaction.Commit();
			}
		}

		private static void LoadEntities(nHydrateModel model, List<TransferModelItem> elements)
		{
			foreach (var tableItem in elements.Where(x => x.ParentId == model.Id && x.ModelTypeId == (int)EntityTypeConstants.Table))
			{
				var modelTableItem = new Entity(model.Partition);
				(modelTableItem as IServiceSavable).FromXml(System.Text.Encoding.UTF8.GetString(tableItem.Data));
				model.Entities.Add(modelTableItem);

				foreach (var fieldItem in elements.Where(x => x.ParentId == tableItem.ElementId && x.ModelTypeId == (int)EntityTypeConstants.TableField))
				{
					var modelFieldItem = new Field(model.Partition);
					(modelFieldItem as IServiceSavable).FromXml(System.Text.Encoding.UTF8.GetString(fieldItem.Data));
					modelTableItem.Fields.Add(modelFieldItem);
				}

			}
		}
		
		public static void Save(nHydrateModel model)
		{
			if (model.SyncServerToken == Guid.Empty)
			{
				model.SyncServerToken = SyncDomain.ShowLoginPrompt(model.SyncServerURL);
				if (model.SyncServerToken == Guid.Empty)
				{
					MessageBox.Show("The server could not be contacted and the model cannot be saved.", "Login Failed", MessageBoxButtons.OK, MessageBoxIcon.Information);
					return;
				}
			}

			var elements = new List<TransferModelItem>();

			var serviceElement = model as IServiceSavable;
			var modelElement = new TransferModelItem()
				                   {
					                   Data = System.Text.Encoding.UTF8.GetBytes(serviceElement.ToXml()),
					                   ElementId = model.Id,
					                   ModelTypeId = (int) EntityTypeConstants.Model,
					                   Versionstamp = serviceElement.Versionstamp,
				                   };
			elements.Add(modelElement);

			SaveEntities(model, elements);

			SyncDomain.SaveModel(model.SyncServerURL, model.SyncServerToken, model.Id, elements.ToArray());
		}

		private static void SaveEntities(nHydrateModel model, List<TransferModelItem> elements)
		{
			foreach (IServiceSavable item in model.Entities)
			{
				elements.Add(new TransferModelItem()
					             {
												 Data = System.Text.Encoding.UTF8.GetBytes(item.ToXml()),
												 ElementId = item.Id,
												 ModelTypeId = (int)EntityTypeConstants.Table,
												 Versionstamp = item.Versionstamp,
												 ParentId = model.Id,
					             });
				SaveFields(item as Entity, elements);
			}
		}

		private static void SaveFields(Entity entity, List<TransferModelItem> elements)
		{
			foreach (IServiceSavable item in entity.FieldList)
			{
				elements.Add(new TransferModelItem()
				{
					Data = System.Text.Encoding.UTF8.GetBytes(item.ToXml()),
					ElementId = item.Id,
					ModelTypeId = (int)EntityTypeConstants.TableField,
					Versionstamp = item.Versionstamp,
					ParentId = entity.Id,
				});
			}
		}

		private static void SaveRelations(Entity entity, List<TransferModelItem> elements)
		{
			foreach (IServiceSavable item in entity.RelationshipList)
			{
				elements.Add(new TransferModelItem()
				{
					Data = System.Text.Encoding.UTF8.GetBytes(item.ToXml()),
					ElementId = item.Id,
					ModelTypeId = (int)EntityTypeConstants.TableField,
					Versionstamp = item.Versionstamp,
					ParentId = entity.Id,
				});
			}
		}

	}
}
